/*
	This file is part of AVRCppLib.

    AVRCppLib is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    AVRCppLib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with AVRCppLib.  If not, see <http://www.gnu.org/licenses/>.

    Copyright (C) Maxime Lemonnier 2007-2011
 */

#ifndef EXTERNALINTERRUPTS_H_
#define EXTERNALINTERRUPTS_H_
#include "../CallbackServers/CallbackConnector.h"
#include "../Utils/CppExtensions.h"
#include "../Utils/BitManipulation.h"

namespace InterruptSenseModes
{
/*!
}
 * External interrupt sense modes
 */
enum InterruptSenseMode
{
	LOGICAL_LOW = 0x00u, 	//!<< a logical low voltage level on this instance's pin triggers an interrupt
	ANY_CHANGE = 0x01, 		//!<< any logical voltage level change on this instance's pin triggers an interrupt
	FALLING_EDGE = 0x02, 	//!<< a logical voltage level that falls from high to low on this instance's pin triggers an interrupt
	RISING_EDGE = 0x03		//!<< a logical voltage level that rises from low to high on this instance's pin triggers an interrupt
};

}

using InterruptSenseModes::InterruptSenseMode;
/*!
 * External interrupt class
 * @remarks this class is a Singleton
 */
class ExternalInterrupt  : public CallbackConnector{
public:



	virtual ~ExternalInterrupt(){}

	/*!
	 * Singleton accessor
	 * @param number the External interrupt pin number
	 * @return the unique instance to ExternalInterrupt for the specified pin number
	 */
	static ExternalInterrupt * getInstance(size_t number);

	inline void enableInterrupt() FORCE_INLINE;
	inline void disableInterrupt() const FORCE_INLINE;
	inline bool readInterruptFlag() const FORCE_INLINE;
	inline void clearInterruptFlag() FORCE_INLINE;

	/*!
	 * Configuration function
	 * @param mode the External interrupt sense mode
	 * @see \a InterruptSenseMode
	 */
	void configure(InterruptSenseMode mode)
	{
		setConfig(eiscr, modeMask, mode);
	}

protected:
	ExternalInterrupt(uint8_t callbackVectorNumber, IOAddress eiscr, InterruptSenseMode mode, uint8_t modeMask, IOAddress eimsk, uint8_t eie, IOAddress eifr, uint8_t eief);
private:


	/*!
	 * External interrupt sense control
	 */
	IOAddress eiscr;

	/*!
	 * The External interrupt sense mode
	 */
	InterruptSenseMode mode;

	/*!
	 * mask for ISC#0 and ISC#1 bits in eiscr
	 */
	uint8_t modeMask;

	/*!
	 * External interrupt mask
	 */
	IOAddress eimsk;

	/*!
	 * External Interrupt enable flag number
	 */
	uint8_t eie;

	/*!
	 * External interrupt flags
	 */
	IOAddress eifr;

	/*!
	 * External interrupt flag number
	 */
	uint8_t eief;

};

#include "ExternalInterrupts-definitions.h"

#endif /* EXTERNALINTERRUPTS_H_ */
